#include<Geometry\BlockMesh.h>
#include<baseClass\GLOG.h>

std::vector<BlockVertex> BlockMesh::LoadMesh_Obj(const char* path)
{
    std::vector<glm::vec3> pos;
    std::vector<glm::vec2> uv;
    std::vector<glm::vec3> nor;
    std::vector<BlockVertex> vertice;
    // Open the file
    std::ifstream file;
    // 保证ifstream对象可以抛出异常：
    file.exceptions (std::ifstream::failbit | std::ifstream::badbit);

    try 
    {
        // 打开文件
        file.open(path);
        std::string line;
        while ( std::getline(file, line)) {

            std::istringstream iss(line);
            std::string type;
            iss >> type;
            if (type == "v") {
                glm::vec3 v;
                iss >> v.x >> v.y >> v.z;
                pos.push_back(v);
            }
            else if (type == "vt") {
                glm::vec2 vt;
                iss >> vt.x >> vt.y;
                uv.push_back(vt);
            }
            else if (type == "vn") {
                glm::vec3 vn;
                iss >> vn.x >> vn.y >> vn.z;
                nor.push_back(vn);
            }
            else if (type == "f") {
            BlockVertex v;
            std::string f;
            while (iss >> f) {
                std::replace(f.begin(), f.end(), '/', ' ');
                std::istringstream vs(f);
                std::string v1, v2, v3;
                vs >> v1 >> v2 >> v3;
                v.position = pos[std::stoi(v1) - 1];
                v.uv = uv[std::stoi(v2) - 1];
                v.normal = nor[std::stoi(v3) - 1];
                vertice.push_back(v);
            }}
        }
        file.close();     
    }
    catch(std::ifstream::failure &e) 
    {
        ERROR(std::string("网格体::OBJ::文件读取失败 ") + e.what());
    }
    return vertice;
}

   
    
BlockMesh::BlockMesh(unordered_map<Texture2D * , vector<BlockVertex>>&& Texture2D_VertexMap)
{
    this->Texture2D_VertexMap = Texture2D_VertexMap;
    vector<BlockVertex> vertices;
    for(auto it = Texture2D_VertexMap.begin(); it != Texture2D_VertexMap.end(); it ++)
    {
        vertices.insert(vertices.end(), it->second.begin(), it->second.end());
    }
    setupMesh(VAO, VBO, vertices);
}



void BlockMesh::setupMesh(uint32_t & VAO,  uint32_t &VBO, vector<BlockVertex>&vertices)
{
    auto mtx = GLGlobal::GetMuetx();
    std::lock_guard<std::mutex> lock(*mtx);

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(BlockVertex), vertices.data(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BlockVertex), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(BlockVertex), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(BlockVertex), (void*)(5 * sizeof(float)));
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(BlockVertex), (void*)(8 * sizeof(float)));
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}



void BlockMesh::Render(Blockshader &shader)
{
    
    
    shader.setMat4("model", this->GetModel());
   
    int PerSize = 0;
    glBindVertexArray(VAO);
    for (auto it = Texture2D_VertexMap.begin(); it != Texture2D_VertexMap.end(); it++)
    {    
        it->first->bind(0);
        glDrawArrays(GL_TRIANGLES,PerSize , it->second.size()); 
        PerSize = PerSize + it->second.size();
    }
    glBindVertexArray(0);

    
}